/**
 * @author:albert
 */

package com.bkbw.live.battle.business.behaviors;

import java.util.HashMap;
import java.util.LinkedList;

import javax.jws.soap.SOAPBinding.ParameterStyle;

import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.bkbw.live.battle.business.BehaviorBase;
import com.bkbw.live.battle.business.BulletObject;
import com.bkbw.live.battle.business.DistanceObject;
import com.bkbw.live.battle.business.GameObject;
import com.bkbw.live.battle.business.UnitObject;
import com.bkbw.live.battle.business.skill.EffectFactory;
import com.bkbw.live.battle.business.skill.effect.DamageEffect;
import com.bkbw.live.battle.business.skill.effect.ShootDamageEffect;
import com.bkbw.live.common.GameConfig;
import com.bkbw.live.common.dataproto.EnumConfigPb.BulletCollisionMode;
import com.bkbw.live.common.dataproto.EnumConfigPb.BulletMoveMode;

public class BulletMoveBehavior extends BehaviorBase {
	Logger logger = LoggerFactory.getLogger(GameConfig.LoggerName);
	
	protected BulletMoveMode moveMode;
	protected BulletCollisionMode collisionMode;
	protected UnitObject srcUnit;
	protected UnitObject dstUnit;
	protected Vector3D srcPos;
	protected Vector3D dstPos;
	protected float missileSpeed;
	protected float bulletRadius = 0.6f;
	protected float bulletRadiusSqr;
	//protected BezierMove curveMove;
	protected BezierMove3 curveMove3;
	
	
	public BezierMove3 getCurveMove3() {
		return curveMove3;
	}

	public void setCurveMove3(BezierMove3 curveMove3) {
		this.curveMove3 = curveMove3;
	}

	public BulletMoveBehavior(HashMap<String, Object> param)
	{
		super(param);
		this.srcUnit = (UnitObject)param.get("srcUnit");
		this.dstUnit = (UnitObject)param.get("dstUnit");
		this.srcPos = (Vector3D)param.get("srcPos");
		this.dstPos = (Vector3D)param.get("dstPos");
		this.missileSpeed = (float)param.get("missileSpeed");
		this.moveMode = (BulletMoveMode)param.get("moveMode");
		this.collisionMode = (BulletCollisionMode)param.get("collisionMode");
		
		bulletRadiusSqr = bulletRadius * bulletRadius;
	}
	
	public void bind(GameObject obj) 
	{
		this.object = obj;
		this.object.setMoving(true);
		calculateSpeedBegin();
	}
	
	public void unbind()
	{
		this.object = null;
	}
	
	public void update(float dt)
	{
		try {
			//calculateSpeed();
			move(dt);
			// TODO 暂时让子弹可以穿，因为服务器和客户端地图没有同步
//			if (!this.object.getMap().canUnitCross((float)this.object.getPosition().getX(), (float)this.object.getPosition().getZ())) {
//				//System.out.println("bullet out of bound");
//				removeBullet();
//				return;
//			}
			doCollision();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	protected void calculateSpeedBegin()
	{
		if (this.moveMode == BulletMoveMode.Line) {
			Vector3D pos = this.dstPos;
			Vector3D vc = pos.subtract(this.object.getPosition());
			//Vector3D vc = this.object.getPosition().subtract(pos);
			if (vc.getNorm() == 0.0D) {
				this.object.setSpeedAndHead(new Vector3D(0, 0, 0));
			}
			else {
				this.object.setSpeedAndHead(vc.normalize().scalarMultiply(this.missileSpeed));
			}
		} else if (this.moveMode == BulletMoveMode.Follow) {
			Vector3D pos = this.dstUnit.getPosition();
			Vector3D vc = pos.subtract(this.object.getPosition());
			//Vector3D vc = this.object.getPosition().subtract(pos);
			if (vc.getNorm() == 0.0D) {
				this.object.setSpeedAndHead(new Vector3D(0, 0, 0));
			}
			else {
				this.object.setSpeedAndHead(vc.normalize().scalarMultiply(this.missileSpeed));
			}
		}
		else if (this.moveMode == BulletMoveMode.Curve) {
			//curveMove3 = new BezierMove3(new Vector3((float)this.srcPos.getX(), 0, (float)this.srcPos.getZ()),
			//		new Vector3((float)this.dstPos.getX(), 0, (float)this.dstPos.getZ()), 5f, this.missileSpeed);
			//curveMove = new BezierMove(new Vector2((float)this.srcPos.getX(), (float)this.srcPos.getZ()),  
			//		new Vector2((float)this.dstPos.getX(), (float)this.dstPos.getZ()), BezierMove.Angle60, this.missileSpeed);
		}
	}
	
	protected void calculateSpeed()
	{
		if (this.moveMode == BulletMoveMode.Line) {
			
		} else if (this.moveMode == BulletMoveMode.Follow) {
			if (!dstUnit.attackable()) {
				return;
			}
			Vector3D pos = this.dstUnit.getPosition();
			Vector3D vc = pos.subtract(this.object.getPosition());
			//Vector3D vc = this.object.getPosition().subtract(pos);
			if (vc.getNorm() == 0.0D) {
				this.object.setSpeedAndHead(new Vector3D(0, 0, 0));
			}
			else {
				this.object.setSpeedAndHead(vc.normalize().scalarMultiply(this.missileSpeed));
			}
			
		}
		else if (this.moveMode == BulletMoveMode.Curve) {
			
		}
	}
	
	protected void move(float dt)
	{
		if (!this.object.isMoving()) {
			return;
		}
		if (this.moveMode == BulletMoveMode.Curve) {
			Vector3 pos = new Vector3();
			Vector3 derivate = new Vector3();
			//if (curveMove.move(dt, pos, derivate)) {
			if (curveMove3.move(dt, pos, derivate)) {
				System.out.println("curve move end " + pos);
				System.out.println("dstpos " + this.dstPos);
			}
			logger.debug("bulletid"+this.object.getId()+" pos "+pos+" derivate "+derivate);
			//this.object.setPosition(new Vector3D(pos.x, 5 * curveMove3.getRate(), pos.y));
			this.object.setPosition(new Vector3D(pos.x, pos.y, pos.z));
			this.object.getMap().bulletMoveNotify(this.object.getId(), this.object.getPosition(),
					new Vector3D(derivate.x, derivate.y, derivate.z), missileSpeed);
			return;
		}
		
		if (this.moveMode == BulletMoveMode.Follow) {
			this.calculateSpeed();
		}
		
		Vector3D speed = this.object.getSpeed();
		Vector3D movement = speed.scalarMultiply(dt);
		Vector3D pos = this.object.getPosition().add(movement);
		this.object.setPosition(pos);
		//System.out.println("bullet " + this.object.getId() + " pos " + this.object.getPosition());
		//System.out.println("bullet " + this.object.getId() + " speed " + speed);
		this.object.getMap().bulletMoveNotify(this.object.getId(), pos, pos, missileSpeed);
		
	}
	
	protected void doCollision()
	{
		if (this.collisionMode == BulletCollisionMode.Any) {
			collisionAny();
		} 
		else if (this.collisionMode == BulletCollisionMode.Enemy) {
			collisionEnemy();
		}
		else if (this.collisionMode == BulletCollisionMode.TargetUnit) {
			collisionTargetUnit();
		}
		else if (this.collisionMode == BulletCollisionMode.TargetPos) {
			// do nothing
			collisionTargetPos();
		}
	}
	
	protected void collisionAny() {
		LinkedList<DistanceObject<UnitObject>> list = this.object.getMap().getUnitsInDistance(this.object, bulletRadius);
		for (DistanceObject<UnitObject> distanceObject : list) {
			UnitObject unitObject = distanceObject.getGameObject();
			if (unitObject != this.srcUnit && unitObject.attackable()) {
				//System.out.println("bullet collisionAny ");
				hit(unitObject);
				removeBullet();
				break;
			}
		}
	}
	
	protected void collisionEnemy() {
		LinkedList<DistanceObject<UnitObject>> list = this.object.getMap().getUnitsInDistance(this.object, bulletRadius);
		for (DistanceObject<UnitObject> distanceObject : list) {
			UnitObject unitObject = distanceObject.getGameObject();
			if (unitObject != this.srcUnit && unitObject.attackable() && this.srcUnit.getGroup() != unitObject.getGroup()) {
				//System.out.println("bullet collisionEnemy ");
				hit(unitObject);
				removeBullet();
				break;
			}
		}
	}
	
	protected void collisionTargetUnit() {
		if (this.dstUnit != null && this.dstUnit.attackable()) {
			float distanceSqr = (float)this.object.getPosition().distanceSq(this.dstUnit.getPosition());
			if (distanceSqr <= bulletRadiusSqr) {
				//System.out.println("bullet collisionTarget ");
				hit(this.dstUnit);
				removeBullet();
			}
		}
	}
	
	protected void collisionTargetPos() {
		if (this.object.getPosition().subtract(this.dstPos).getNormSq() <= GameConfig.Epsilon) {
			LinkedList<DistanceObject<UnitObject>> list = this.object.getMap().getEnemysInDistance(this.object, 3);
			for (DistanceObject<UnitObject> distanceObject : list) {
				UnitObject unitObject = distanceObject.getGameObject();
				if (unitObject.attackable() && this.srcUnit.getGroup() != unitObject.getGroup()) {
					//System.out.println("bullet collisionEnemy ");
					hit(unitObject);
				}
			}
			removeBullet();
		}
	}
	
	protected void hit(UnitObject unit)
	{
		HashMap<String, Object> param = new HashMap<String, Object>();
		param.put("source", this.srcUnit);
		param.put("target", unit);
		//ShootDamageEffect effect = (ShootDamageEffect)EffectFactory.getInstance().createEffect("ShootDamageEffect", param);
		ShootDamageEffect effect = new ShootDamageEffect(param);
		effect.applyEffect();
		//System.out.println("bullet move hit enemy " + this.object.getId());
	}
	
	protected void removeBullet()
	{
		//System.out.println("removebullet");
		this.srcUnit.getMap().removeBullet((BulletObject)this.object);
	}
}
